package de.kuttenmann.jflake;
import java.util.LinkedList;
import java.util.List;

public class SceneBuilder
{
	public static Node create(int level, Vector3D c, Vector3D d, double r)
	{
		/* if not at the bottom, recurse a bit more */
		List<Node> subNodes = new LinkedList<Node>();
		if (level > 0)
		{
			Basis b = new Basis(d);
			double nr = r * 1 / 3.0;
			double daL = 2.0 * Math.PI / 6.0;
			double daU = 2.0 * Math.PI / 3.0;
			double a = 0.0;
			/* lower ring */
			for (int i = 0; i < 6; ++i)
			{
				Vector3D ndir =
					d.scale(-0.2).add(b.b1.scale(Math.sin(a))).add(b.b2.scale(Math.cos(a))).normalize();
				subNodes.add(create(level - 1, c.add(ndir.scale(r + nr)), ndir, nr));
				a += daL;
			}
			a -= daL / 3.0;
			/* upper ring */
			for (int i = 0; i < 3; ++i)
			{
				Vector3D ndir =
					d.scale(0.6).add(b.b1.scale(Math.sin(a))).add(b.b2.scale(Math.cos(a))).normalize();
				subNodes.add(create(level - 1, c.add(ndir.scale(r + nr)), ndir, nr));
				a += daU;
			}
		}
		// create new node and return
		return new Node(new Sphere(c, 2.0*r), new Sphere(c, r), subNodes);
	}

	private static class Basis
	{
		Vector3D b1;
		Vector3D b2;

		private Basis(Vector3D up)
		{
			Vector3D normal = up.normalize();
			double x = normal.getX();
			double y = normal.getY();
			double z = normal.getZ();

			final double nx2 = normal.getX() * normal.getX();
			final double ny2 = normal.getY() * normal.getY();
			final double nz2 = normal.getZ() * normal.getZ();

			if ((nx2 != 1.0) && (ny2 != 1.0) && (nz2 != 1.0))
			{
				if (ny2 > nx2)
				{
					if (ny2 > nz2)
					{
						y = -y;
					}
					else
					{
						z = -z;
					}
				}
				else if (nz2 > nx2)
				{
					z = -z;
				}
				else
				{
					x = -x;
				}
				b1 = new Vector3D(x, y, z);
			}
			else
			{
				b1 = new Vector3D(z, x, y); /* leaves some cases out,dodge them */
			}

			b2 = normal.cross(b1);
			b1 = normal.cross(b2);
		}
	}
}
